package com.siebre.picclife.asynctask.springconfig;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.common.base.Predicate;
import com.siebre.bmf.core.BmfPrimitiveType2;
import com.siebre.picclife.asynctask.service.support.ArgumentDeserializer;
import com.siebre.picclife.asynctask.service.support.ArgumentSerializer;
import com.siebre.picclife.asynctask.service.support.TaskArgumentHandlerManager;
import com.siebre.picclife.asynctask.service.support.TaskArgumentHandlerRegistrar;
import com.siebre.repository.GeneralRepository;
import com.siebre.repository.utils.EntityUtils;
import com.siebre.util.BeanPropertyUtils;

/**
 * 
 * @author ZhangChi
 * @since 2015年4月9日
 *
 */
@Configuration
public class TaskArgumentHandlerConfig {
	
	@Autowired(required = false)
	private List<TaskArgumentHandlerRegistrar> registrars = Collections.emptyList();

	@Bean
	TaskArgumentHandlerManager taskArgumentHandlerManager(final GeneralRepository generalRepository) {
		TaskArgumentHandlerManager result = new TaskArgumentHandlerManager();
		for (TaskArgumentHandlerRegistrar registrar : registrars) {
			registrar.register(result);
		}
		
		result.register(Serializable.class, new ArgumentSerializer() {
			
			public String serialize(Object argument) {
				return argument.toString();
			}
		}, new ArgumentDeserializer() {
			
			public Object deserialize(String serialized, Class<?> type) {
				return BmfPrimitiveType2.valueOf(type).convert(serialized);
			}
		});
		
		result.register(new Predicate<Class<?>>() {
			
			public boolean apply(Class<?> argumentType) {
				return EntityUtils.isEntityType(argumentType);
			}
		}, new ArgumentSerializer() {

			public String serialize(Object descriptor) {
				String idPropertyName = EntityUtils.resolveIdProperty(descriptor.getClass());
				if (idPropertyName == null) {
					return null;
				}
				Object id = BeanPropertyUtils.propertyOf(descriptor).withName(idPropertyName).value();
				if (id == null) {
					throw new IllegalArgumentException("entity id of descriptor is null, descriptor=" + descriptor);
				}
				return id.toString();
			}
		}, new ArgumentDeserializer() {
			
			public Object deserialize(String serialized, Class<?> type) {
				Object result = generalRepository.findOne(type, Long.parseLong(serialized));
				Hibernate.initialize(result);//trigger initialization
				return result;
			}
		});
		
//		result.register("default", new ArgumentSerializer() {
//
//			public String serialize(Object descriptor) {
//				if (EntityUtils.isEntityType(descriptor.getClass())) {
//					String idPropertyName = EntityUtils.resolveIdProperty(descriptor.getClass());
//					if (idPropertyName == null) {
//						return null;
//					}
//					Object id = BeanPropertyUtils.propertyOf(descriptor).withName(idPropertyName).value();
//					if (id == null) {
//						throw new IllegalArgumentException("entity id of descriptor is null, descriptor=" + descriptor);
//					}
//					return id.toString();
//				}
//				return null;
//			}
//		}, new ArgumentDeserializer() {
//			
//			public Object deserialize(String serialized, Class<?> type) {
//				Object result = generalRepository.findOne(type, Long.parseLong(serialized));
//				Hibernate.initialize(result);//trigger initialization
//				return result;
//			}
//		});
		return result;
	}
}
